#region license
// Copyright (c) 2007 Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Rodrigo B. de Oliveira nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Taken and modified from ConcurrentBoo

# This file is part of Grawlix.
# 
# Grawlix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# 
# Grawlix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with Grawlix.  If not, see
# <http://www.gnu.org/licenses/>.
#endregion

"""Computation object for holding the results of an operation."""

namespace ConcurrentBoo
import System
import System.Threading
	
transient class Computation:
"""Storage of the results of a computation."""
	
	Finished:
	"""Whether the computation is complete."""
		[lock]
		get:
			return _finished
		
	Value:
	"""
	Retrieves the value of the computation blocking until it's available.
	Returns: The computed value.
	Raises ComputationFailureException: When the computation
		terminates exceptionally.
	"""
		[lock]
		get:
			EnsureFinished()
			EnsureSuccessful()
			return _value
		
		[lock]
		set:
			_value = value
			NotifyFinished()
			
	Failure:
	"""
	The exception if any that caused the computation to fail,
	blocking until it's available.
	"""
		[lock]
		get:
			EnsureFinished()
			return _failure
		
		[lock]
		set:
			_failure = value
			NotifyFinished()	
	
	[lock]
	def Wait(timeout as timespan):
	"""
	Blocks until the computation is finished or millisecondsTimeout is elapsed.
	Param timeout: The maximum amount of time to wait.
	"""
		return EnsureFinished(timeout.Milliseconds)
	
	[lock]
	def Wait(millisecondsTimeout as int):
	"""
	Blocks until the computation is finished or millisecondsTimeout is elapsed.
	Param millisecondsTimeout: The maximum amount of time to wait.
	"""
		return EnsureFinished(millisecondsTimeout)		
	
	[lock]
	def Wait():	
	"""
	Blocks until the computation is finished. Same as Wait(Timeout.Infinite).
	"""
		EnsureFinished()
	
	private def EnsureFinished():
	"""Wait indefinitely for the results."""
		assert EnsureFinished(Timeout.Infinite)
	
	private def EnsureFinished(millisecondsTimeout as int):
	"""
	Wait for the operation to finish, or for the time out.
	Param millisecondsTimeout: The max amount of time to wait.
	"""
		if _finished: return true
		return Monitor.Wait(self, millisecondsTimeout)
		
	private def EnsureSuccessful():
	"""Check that the operation has completed in success."""
		if _failure is null: return
		raise ComputationFailureException(
			"Exception raised during asynchronous execution.\n",
			_failure)
		
	private def NotifyFinished():
	"""Notify that the operation has completed."""
		_finished = true
		Monitor.PulseAll(self)

	private _failure as Exception
	"""If an exception was raised, this is that exception."""
	
	private _value
	"""The result of the computation."""
	
	private _finished as bool
	"""Set true when the computation is ready."""
	

